﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;
using System.Threading.Tasks;
using System.Windows.Input;
using Grpc.Core;
using Grpc.Core.Interceptors;
using Plugin.Permissions;
using Plugin.Permissions.Abstractions;
using Xamarin.Forms;
using Permission = Plugin.Permissions.Abstractions.Permission;

namespace mb
{
    public class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void FirePropertyChangedEvent(string propertyName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public static class ForEachHelper
    {
        public sealed class Item<T>
        {
            public int Index { get; set; }
            public T Value { get; set; }
            public bool IsLast { get; set; }
        }

        public static IEnumerable<Item<T>> WithIndex<T>(IEnumerable<T> enumerable)
        {
            Item<T> item = null;
            foreach (T value in enumerable)
            {
            Item<T> next = new Item<T>();
            next.Index = 0;
            next.Value = value;
            next.IsLast = false;
            if (item != null)
            {
            next.Index = item.Index + 1;
            yield return item;
                }
                item = next;
            }

            if (item != null)
            {
                item.IsLast = true;
                yield return item;
            }
        }
    }

    public static class AssemblyCreationDate
    {
        public static readonly DateTime Value;
        static AssemblyCreationDate()
        {
            Version version = Assembly.GetExecutingAssembly().GetName().Version;
            // days since 1 January 2000 , seconds since midnight, (multiply by 2 to get original)
            Value = new DateTime(2000, 1, 1).Add(new TimeSpan(
                TimeSpan.TicksPerDay * version.Build +
                TimeSpan.TicksPerSecond * 2 * version.Revision));
        }
    }

    public static partial class Util
    {

        static Util()
        {

        }

        public static int HasTestFlag = -2; //-2为未初始化，-1为初始化中，0为否，1为有
        public static async void DoWhenTestFlag(Action actYes = null, Action actNo = null)
        {
            if (HasTestFlag == -2)
            {
                HasTestFlag = -1;
#if __IOS__
                if (mb.iOS.Util.IsSimulator() || (await HasTestContact()))
                    HasTestFlag = 1;
                else
                    HasTestFlag = 0;
#elif __ANDROID__
                if (mb.Droid.Util.isEmulator() || (await mb.Droid.Util.HasPermission(Permission.Contacts) && await HasTestContact()))
                    HasTestFlag = 1;
                else
                    HasTestFlag = 0;
#endif
                App.logger.Log("FirstCheckTestFlag", HasTestFlag);
            }
            else if (HasTestFlag == -1)
            {
                while (HasTestFlag == -1)
                {
                    await Task.Delay(1000);
                }
            }

            if (HasTestFlag == 1)
                actYes?.Invoke();
            else if (HasTestFlag == 0)
                actNo?.Invoke();
        }

        public static async Task<bool> HasTestContact()
        {
            var contacts = await Plugin.ContactService.CrossContactService.Current.GetContactListAsync();
            foreach (var c in contacts)
            {
                if (c.Name.ToLower().IndexOf("xiaoting188") >= 0)
                {
                    return true;
                }
            }
            return false;
        }
        public static string Encrypt(string originalString, byte[] passwd)
        {
            if (String.IsNullOrEmpty(originalString))
                return originalString;

            DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
            MemoryStream memoryStream = new MemoryStream();
            CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoProvider.CreateEncryptor(passwd, passwd), CryptoStreamMode.Write);
            StreamWriter writer = new StreamWriter(cryptoStream);
            writer.Write(originalString);
            writer.Flush();
            cryptoStream.FlushFinalBlock();
            writer.Flush();
            return Convert.ToBase64String(memoryStream.GetBuffer(), 0, (int) memoryStream.Length);
        }

        public static string Decrypt(string cryptedString, byte[] passwd)
        {
            if (String.IsNullOrEmpty(cryptedString))
                return cryptedString;

            DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
            MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(cryptedString));
            CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoProvider.CreateDecryptor(passwd, passwd), CryptoStreamMode.Read);
            StreamReader reader = new StreamReader(cryptoStream);
            return reader.ReadToEnd();
        }

        public static void BufferFlip(byte[] buffer, int nbytes, byte[] key, long koff)
        {
            for (int i = 0; i < nbytes; i++, koff++)
                buffer[i] = (byte) (buffer[i] ^ key[koff % key.Length]);
        }
    }

    public class DeadlineInterceptor : Interceptor
    {
        int timeoutSecond;

        public DeadlineInterceptor(int second)
        {
            timeoutSecond = second;
        }

        public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
        {
            // callback();
            App.logger.Log("intercept unary call........", context.Method.FullName);
            var co = context.Options.WithDeadline(DateTime.UtcNow.AddSeconds(timeoutSecond));
            var ctx = new ClientInterceptorContext<TRequest, TResponse>(context.Method, context.Host, co);
            return continuation(request, ctx);
        }
    }
}